home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
MacHack 2000
/
MacHack 2000.toast
/
pc
/
The Hacks
/
Mac OS X Throbber
/
Source
/
GDeviceUtils.cp
< prev
next >
Wrap
Text File
|
2000-06-23
|
12KB
|
483 lines
/*------------------------------------------------------------------------------
#
# GDeviceUtils.cp
#
# by Eric Traut
#
------------------------------------------------------------------------------*/
#include "GDeviceUtils.h"
#include <Memory.h>
#include <LowMem.h>
#include <Displays.h>
#include <Traps.h>
/*---------------------------------------------------------------
GraphicSurface
---------------------------------------------------------------*/
GraphicSurface::GraphicSurface()
{
// Nothing to do
mPixelData = NULL;
}
/*---------------------------------------------------------------
ExtractRealDeviceInfo
---------------------------------------------------------------*/
void
GraphicSurface::ExtractRealDeviceInfo(
GDHandle inGDevice)
{
PixMapHandle pixMap;
pixMap = inGDevice[0]->gdPMap;
mRowBytes = pixMap[0]->rowBytes & 0x3FFF;
mPixelData = (UInt8 *)pixMap[0]->baseAddr;
mBitDepth = pixMap[0]->pixelSize;
mHeight = pixMap[0]->bounds.bottom - pixMap[0]->bounds.top;
mWidth = pixMap[0]->bounds.right - pixMap[0]->bounds.left;
}
/*---------------------------------------------------------------
CapturedGDevice
---------------------------------------------------------------*/
CapturedGDevice::CapturedGDevice()
{
mGDHandle = NULL;
mDeviceCaptured = false;
mVirtualDeviceList = NULL;
mVirtualDeviceCount = 0;
mBlendEffect = NULL;
}
/*---------------------------------------------------------------
~CapturedGDevice
---------------------------------------------------------------*/
CapturedGDevice::~CapturedGDevice()
{
if (mDeviceCaptured)
UncaptureDevice();
}
/*---------------------------------------------------------------
CaptureDevice
---------------------------------------------------------------*/
void
CapturedGDevice::CaptureDevice(
GDHandle inGDevice,
VirtualGDevice ** inVDeviceList,
UInt32 inVDeviceCount)
{
HideCursor();
if (mDeviceCaptured)
UncaptureDevice();
mGDHandle = inGDevice;
OSErr err = ::DMGetDisplayIDByGDevice(inGDevice, &mDisplayID, false);
if (err != noErr)
DebugStr("\pCouldn't get DisplayID");
mCapturedSurface.ExtractRealDeviceInfo(mGDHandle);
// For now, we only support 16-bit mode.
if (mCapturedSurface.GetBitDepth() != 16)
{
// fix me - report an error
}
else
{
mVirtualDeviceList = inVDeviceList;
mVirtualDeviceCount = inVDeviceCount;
// Tell each of the virtual monitors to initialize
// itself. Initialize in reverse order because
// the display manager orders them that way.
for (SInt32 vDeviceIndex = inVDeviceCount - 1; vDeviceIndex >= 0; vDeviceIndex--)
inVDeviceList[vDeviceIndex]->Initialize(*this, vDeviceIndex);
err = ::DMSetMainDisplay(inVDeviceList[0]->GetGDHandle(), NULL);
if (err != noErr)
DebugStr("\p Error SetMainDisplay");
RecomputeGDHandle();
// We need to recompute the GDHandles from the display IDs
// because they may have been rearranged.
for (UInt32 vDeviceIndex = 0; vDeviceIndex < inVDeviceCount; vDeviceIndex++)
inVDeviceList[vDeviceIndex]->RecomputeGDHandle();
// Now position the displays (Can't move main display)
for (SInt32 vDeviceIndex = 1; vDeviceIndex < inVDeviceCount; vDeviceIndex++)
{
Rect newPos;
inVDeviceList[vDeviceIndex]->GetPreferredPosition(newPos);
err = ::DMMoveDisplay(inVDeviceList[vDeviceIndex]->GetGDHandle(), newPos.left, newPos.top, NULL);
if (err != noErr)
DebugStr("\pMoveDisplay failed");
}
// Now get rid of the rounded area in the corners
RgnHandle rgn = NewRgn();
RgnHandle grayRgn = LMGetGrayRgn();
for (SInt32 vDeviceIndex = 0; vDeviceIndex < inVDeviceCount; vDeviceIndex++) {
GDHandle gdHandle = inVDeviceList[vDeviceIndex]->GetGDHandle();
SetDeviceAttribute(gdHandle, roundedDevice, false);
Rect r = (**gdHandle).gdRect;
if (r.left == 0 && r.top == 0) r.top = GetMBarHeight();
RectRgn(rgn, &r);
MacUnionRgn(grayRgn, rgn, grayRgn);
}
DisposeRgn(rgn);
CWindowRecord wr;
CWindowPtr wp = (CWindowPtr)NewCWindow(&wr, &(**LMGetGrayRgn()).rgnBBox, "\p ", true, plainDBox, 0, false, 237);
CloseWindow((WindowPtr)wp);
mDeviceCaptured = true;
}
ShowCursor();
}
/*---------------------------------------------------------------
UncaptureDevice
---------------------------------------------------------------*/
void
CapturedGDevice::UncaptureDevice()
{
if (mDeviceCaptured)
{
RecomputeGDHandle();
OSErr err = ::DMSetMainDisplay(mGDHandle, NULL);
if (err != noErr)
DebugStr("\p Error SetMainDisplay");
RecomputeGDHandle();
// Tell each of the virtual monitors to
// uninitialize itself.
for (UInt32 vDeviceIndex = 0; vDeviceIndex < mVirtualDeviceCount; vDeviceIndex++)
{
if (mVirtualDeviceList[vDeviceIndex] != NULL)
mVirtualDeviceList[vDeviceIndex]->Uninitialize();
}
mDeviceCaptured = false;
}
}
/*---------------------------------------------------------------
UncaptureDevice
---------------------------------------------------------------*/
void
CapturedGDevice::SetPixelBase(
UInt8 * inPixelBase)
{
PixMapHandle pixMap;
RecomputeGDHandle();
if (mGDHandle != NULL)
{
pixMap = mGDHandle[0]->gdPMap;
pixMap[0]->baseAddr = (Ptr)inPixelBase;
}
}
/*---------------------------------------------------------------
UpdateCapturedScreen
---------------------------------------------------------------*/
void
CapturedGDevice::UpdateCapturedScreen()
{
if (mBlendEffect != NULL)
{
mBlendEffect->BlendVirtualDevices(
mCapturedSurface,
mVirtualDeviceList,
mVirtualDeviceCount);
}
}
/*---------------------------------------------------------------
RecomputeGDHandle
---------------------------------------------------------------*/
void
CapturedGDevice::RecomputeGDHandle()
{
OSErr err;
err = ::DMGetGDeviceByDisplayID(mDisplayID, &mGDHandle, false);
if (err != noErr)
{
DebugStr("\pFailedToFindDevice");
mGDHandle = NULL;
}
}
/*---------------------------------------------------------------
SetGraphicBlendEffect
---------------------------------------------------------------*/
void
CapturedGDevice::SetGraphicBlendEffect(
GraphicBlendEffect * inBlendEffect)
{
if (mBlendEffect != NULL)
{
GraphicBlendEffect * tempEffect = mBlendEffect;
// Set it to NULL first so time manager
// task doesn't call the effect after it's
// deallocated.
mBlendEffect = NULL;
delete tempEffect;
}
// We need to wipe the dest screen to black
ClearCapturedScreen();
mBlendEffect = inBlendEffect;
}
/*---------------------------------------------------------------
SetGraphicBlendValue
---------------------------------------------------------------*/
void
CapturedGDevice::SetGraphicBlendValue(
UInt32 inValueIndex,
double inValue)
{
if (mBlendEffect != NULL)
{
mBlendEffect->SetEffectValue(inValueIndex, inValue);
}
}
/*---------------------------------------------------------------
ClearCapturedScreen
---------------------------------------------------------------*/
void
CapturedGDevice::ClearCapturedScreen()
{
// The simple blend effect simply involves
// copying the pixels from the first virtual
// device to the destination surface.
UInt32 totalRows = mCapturedSurface.GetHeight();
UInt32 totalCols = mCapturedSurface.GetWidth();
UInt8 * destPtr;
for (UInt32 row = 0; row < totalRows; row++)
{
destPtr = mCapturedSurface.GetPixelDataPtr() + mCapturedSurface.GetRowBytes() * row;
for (UInt32 col = 0; col < totalCols; col++)
{
*(UInt16 *)destPtr = 0;
destPtr += 2;
}
}
}
/*---------------------------------------------------------------
VirtualGDevice
---------------------------------------------------------------*/
VirtualGDevice::VirtualGDevice()
{
mDeviceBacking = NULL;
mGDHandle = NULL;
mAddedToDeviceList = false;
}
/*---------------------------------------------------------------
~VirtualGDevice
---------------------------------------------------------------*/
VirtualGDevice::~VirtualGDevice()
{
Uninitialize();
}
/*---------------------------------------------------------------
Initialize
---------------------------------------------------------------*/
Boolean
VirtualGDevice::Initialize(
CapturedGDevice & inRealGDevice,
UInt32 inIndex)
{
// Allocate backing memory for the virtual device
Ptr backingPtr;
backingPtr = ::NewPtrClear(inRealGDevice.GetGraphicSurface().GetBackingSize());
if (backingPtr == NULL)
return false;
mDeviceBacking = backingPtr;
// Allocate a new GDevice if this isn't the primary
// virtual device.
// fix me - what is the first parameter?
mGDHandle = ::NewGDevice(0, -1);
if (mGDHandle == NULL)
return false;
::HLock((Handle)mGDHandle);
Handle itableHandle;
itableHandle = ::NewHandle(0);
if (itableHandle == NULL)
return false;
// Make a default inverse table
::MakeITable(NULL, (ITabHandle)itableHandle, 4);
mGDHandle[0]->gdRefNum = 0;
mGDHandle[0]->gdID = 1024 + inIndex;
mGDHandle[0]->gdType = 2;
mGDHandle[0]->gdITable = (ITabHandle)itableHandle;
mGDHandle[0]->gdFlags = (1L << gdDevType) | // Color device
(1L << noDriver) | // No driver
(1L << screenDevice) | // It's a screen device (not printer)
(1L << screenActive) | // It's active
(1L << burstDevice) |
(1L << allInit);
mGDHandle[0]->gdMode = 129;
// Set up the device rectangle
mGDHandle[0]->gdRect.left = (inIndex % 2) * inRealGDevice.GetGraphicSurface().GetWidth();
mGDHandle[0]->gdRect.top = (inIndex / 2) * inRealGDevice.GetGraphicSurface().GetHeight();
mGDHandle[0]->gdRect.right = mGDHandle[0]->gdRect.left + inRealGDevice.GetGraphicSurface().GetWidth();
mGDHandle[0]->gdRect.bottom = mGDHandle[0]->gdRect.top + inRealGDevice.GetGraphicSurface().GetHeight();
mPreferredPos = mGDHandle[0]->gdRect;
// Now, set up the pix map for the gdevice
PixMapHandle realPixMap = inRealGDevice.GetPixMapHandle();
PixMapHandle virtPixMap = mGDHandle[0]->gdPMap;
// Copy the pix map info
virtPixMap[0]->baseAddr = mDeviceBacking;
virtPixMap[0]->rowBytes = realPixMap[0]->rowBytes;
virtPixMap[0]->bounds = realPixMap[0]->bounds;
virtPixMap[0]->pmVersion = realPixMap[0]->pmVersion;
virtPixMap[0]->packType = realPixMap[0]->packType;
virtPixMap[0]->packSize = realPixMap[0]->packSize;
virtPixMap[0]->hRes = realPixMap[0]->hRes;
virtPixMap[0]->vRes = realPixMap[0]->vRes;
virtPixMap[0]->pixelType = realPixMap[0]->pixelType;
virtPixMap[0]->pixelSize = realPixMap[0]->pixelSize;
virtPixMap[0]->cmpCount = realPixMap[0]->cmpCount;
virtPixMap[0]->cmpSize = realPixMap[0]->cmpSize;
virtPixMap[0]->planeBytes = realPixMap[0]->planeBytes;
virtPixMap[0]->pmReserved = realPixMap[0]->pmReserved;
if (virtPixMap[0]->pmTable != NULL)
virtPixMap[0]->pmTable[0]->ctFlags = 0x8000;
DMAddDisplay(
mGDHandle,
mGDHandle[0]->gdRefNum,
mGDHandle[0]->gdMode,
0,
0,
NULL,
NULL);
DMEnableDisplay(mGDHandle, NULL);
OSErr err = ::DMGetDisplayIDByGDevice(mGDHandle, &mDisplayID, false);
if (err != noErr)
DebugStr("\pCouldn't get DisplayID");
mAddedToDeviceList = true;
mVirtualSurface.ExtractRealDeviceInfo(mGDHandle);
return true;
}
/*---------------------------------------------------------------
Uninitialize
---------------------------------------------------------------*/
void
VirtualGDevice::Uninitialize()
{
if (mDeviceBacking != NULL)
{
if (mAddedToDeviceList)
{
RecomputeGDHandle();
::DMRemoveDisplay(mGDHandle, NULL);
mAddedToDeviceList = false;
}
if (mGDHandle != NULL)
::DisposeGDevice(mGDHandle);
mGDHandle = NULL;
::DisposePtr(mDeviceBacking);
mDeviceBacking = NULL;
}
}
/*---------------------------------------------------------------
RecomputeGDHandle
---------------------------------------------------------------*/
void
VirtualGDevice::RecomputeGDHandle()
{
OSErr err;
err = ::DMGetGDeviceByDisplayID(mDisplayID, &mGDHandle, false);
if (err != noErr)
{
DebugStr("\pFailedToFindDevice");
mGDHandle = NULL;
}
else
{
// Reset the backing address. It seems
// to get reset when we set the main device.
mGDHandle[0]->gdPMap[0]->baseAddr = mDeviceBacking;
}
}